//! 配置管理模块
//!
//! 提供 TOML 配置文件解析和配置结构体定义。
//!
//! ## 子模块
//!
//! - `parser` - TOML 配置文件解析器
//! - `types` - 配置结构体定义
//!
//! ## 主要类型
//!
//! - [`Log4rConfig`] - 主配置结构体
//! - [`AppendersConfig`] - Appender 配置集合
//! - [`ConsoleConfig`] - 控制台输出配置
//! - [`FileConfig`] - 文件输出配置
//! - [`FormatConfig`] - 格式化配置
//! - [`AsyncConfig`] - 异步配置
//! - [`ConsoleTarget`] - 控制台输出目标枚举
//! - [`TimeZone`] - 时区枚举
//!
//! ## 主要函数
//!
//! - [`parse_config`] - 从 TOML 字符串解析配置
//! - [`load_config`] - 从指定路径加载配置文件
//! - [`find_config`] - 查找默认配置文件
//! - [`load_config_from_default`] - 从默认位置加载配置
//!
//! ## 示例
//!
//! ```rust
//! use log4r::config::{Log4rConfig, ConsoleTarget, TimeZone, parse_config};
//! use log4r::Level;
//!
//! // 使用默认配置
//! let config = Log4rConfig::default();
//! assert_eq!(config.level, Level::Info);
//!
//! // 从 TOML 字符串解析配置
//! let toml = r#"
//! [log4r]
//! level = "debug"
//! app_name = "my-app"
//! "#;
//! let config = parse_config(toml).expect("解析应成功");
//! assert_eq!(config.level, Level::Debug);
//! ```

pub mod parser;
pub mod types;

use std::fs;
use std::path::{Path, PathBuf};

use crate::error::Log4rError;

// 重导出所有公共类型
pub use parser::parse_config;
pub use types::{
    parse_size, AppendersConfig, AsyncConfig, BackpressureStrategy, ConsoleConfig, ConsoleTarget,
    FileConfig, FormatConfig, Log4rConfig, TimeZone,
};

/// 查找默认配置文件
///
/// 按以下顺序查找配置文件：
/// 1. `./log4r.toml` - 当前工作目录
/// 2. `./config/log4r.toml` - config 子目录
/// 3. `~/.config/log4r/log4r.toml` (Unix) 或 `%APPDATA%/log4r/log4r.toml` (Windows)
///
/// # Returns
///
/// * `Some(PathBuf)` - 找到的配置文件路径
/// * `None` - 未找到配置文件
///
/// # Example
///
/// ```rust
/// use log4r::config::find_config;
///
/// if let Some(path) = find_config() {
///     println!("找到配置文件: {}", path.display());
/// } else {
///     println!("未找到配置文件，使用默认配置");
/// }
/// ```
pub fn find_config() -> Option<PathBuf> {
    // 查找顺序：当前目录 → config 子目录
    let candidates = [
        PathBuf::from("log4r.toml"),
        PathBuf::from("config/log4r.toml"),
    ];

    // 检查当前目录和 config 子目录
    for path in &candidates {
        if path.exists() {
            return Some(path.clone());
        }
    }

    // 检查用户配置目录
    if let Some(config_dir) = dirs::config_dir() {
        let user_config = config_dir.join("log4r").join("log4r.toml");
        if user_config.exists() {
            return Some(user_config);
        }
    }

    None
}

/// 从指定路径加载配置文件
///
/// 支持多种路径类型，包括 `&str`、`String`、`&Path` 和 `PathBuf`，
/// 同时支持相对路径和绝对路径。
///
/// # Arguments
///
/// * `path` - 配置文件路径，支持以下类型：
///   - `&str` - 字符串切片，如 `"log4r.toml"`
///   - `String` - 字符串，如 `String::from("config/log4r.toml")`
///   - `&Path` - 路径引用
///   - `PathBuf` - 路径缓冲区
///
/// # Returns
///
/// * `Ok(Log4rConfig)` - 解析成功的配置
/// * `Err(Log4rError::IoError)` - 文件不存在或无法读取
/// * `Err(Log4rError::ConfigError)` - TOML 解析失败或配置无效
///
/// # Examples
///
/// 使用 `&str` 路径：
///
/// ```rust,no_run
/// use log4r::config::load_config;
///
/// let config = load_config("log4r.toml").expect("加载配置失败");
/// println!("日志级别: {:?}", config.level);
/// ```
///
/// 使用 `String` 路径：
///
/// ```rust,no_run
/// use log4r::config::load_config;
///
/// let path = String::from("config/log4r.toml");
/// let config = load_config(&path).expect("加载配置失败");
/// ```
///
/// 使用 `PathBuf` 路径：
///
/// ```rust,no_run
/// use log4r::config::load_config;
/// use std::path::PathBuf;
///
/// let path = PathBuf::from("/etc/myapp/log4r.toml");
/// let config = load_config(&path).expect("加载配置失败");
/// ```
///
/// # Errors
///
/// * [`Log4rError::IoError`] - 文件不存在、权限不足或其他 I/O 错误
/// * [`Log4rError::ConfigError`] - TOML 语法错误、字段类型错误或无效的日志级别
pub fn load_config(path: impl AsRef<Path>) -> Result<Log4rConfig, Log4rError> {
    let path = path.as_ref();
    let content = fs::read_to_string(path).map_err(|e| {
        // 创建包含文件路径信息的 IoError
        std::io::Error::new(
            e.kind(),
            format!("无法读取配置文件 '{}': {}", path.display(), e),
        )
    })?;
    parse_config(&content)
}

/// 从默认位置加载配置
///
/// 首先调用 [`find_config`] 查找配置文件，找到则加载，
/// 未找到则返回默认配置。
///
/// # Returns
///
/// * `Ok(Log4rConfig)` - 加载或默认的配置
/// * `Err(Log4rError)` - 配置文件存在但解析失败
///
/// # Example
///
/// ```rust
/// use log4r::config::load_config_from_default;
///
/// let config = load_config_from_default().expect("加载配置失败");
/// println!("日志级别: {:?}", config.level);
/// ```
pub fn load_config_from_default() -> Result<Log4rConfig, Log4rError> {
    match find_config() {
        Some(path) => load_config(path),
        None => Ok(Log4rConfig::default()),
    }
}

#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
    use super::*;
    use serial_test::serial;
    use std::env;
    use tempfile::tempdir;

    // AC-3.3.4: 无配置文件时返回 None
    #[test]
    #[serial]
    fn test_find_config_returns_none_when_no_config() {
        // 在临时目录中运行，确保没有配置文件
        let temp = tempdir().expect("创建临时目录失败");
        let original_dir = env::current_dir().expect("获取当前目录失败");
        env::set_current_dir(&temp).expect("切换目录失败");

        let result = find_config();
        assert!(result.is_none(), "无配置文件时应返回 None");

        // 恢复原目录
        env::set_current_dir(original_dir).expect("恢复目录失败");
    }

    // AC-3.3.1: 优先查找当前目录
    #[test]
    #[serial]
    fn test_find_config_prefers_current_dir() {
        let temp = tempdir().expect("创建临时目录失败");
        let original_dir = env::current_dir().expect("获取当前目录失败");
        env::set_current_dir(&temp).expect("切换目录失败");

        // 创建 ./log4r.toml
        fs::write("log4r.toml", "[log4r]\nlevel = \"debug\"").expect("写入文件失败");

        let result = find_config();
        assert!(result.is_some(), "应找到配置文件");
        assert_eq!(result.unwrap(), PathBuf::from("log4r.toml"));

        // 恢复原目录
        env::set_current_dir(original_dir).expect("恢复目录失败");
    }

    // AC-3.3.1: 其次查找 config 子目录
    #[test]
    #[serial]
    fn test_find_config_checks_config_subdir() {
        let temp = tempdir().expect("创建临时目录失败");
        let original_dir = env::current_dir().expect("获取当前目录失败");
        env::set_current_dir(&temp).expect("切换目录失败");

        // 创建 ./config/log4r.toml
        fs::create_dir("config").expect("创建目录失败");
        fs::write("config/log4r.toml", "[log4r]\nlevel = \"info\"").expect("写入文件失败");

        let result = find_config();
        assert!(result.is_some(), "应找到配置文件");
        assert_eq!(result.unwrap(), PathBuf::from("config/log4r.toml"));

        // 恢复原目录
        env::set_current_dir(original_dir).expect("恢复目录失败");
    }

    // AC-3.3.5: 找到第一个后立即返回
    #[test]
    #[serial]
    fn test_find_config_returns_first_found() {
        let temp = tempdir().expect("创建临时目录失败");
        let original_dir = env::current_dir().expect("获取当前目录失败");
        env::set_current_dir(&temp).expect("切换目录失败");

        // 创建两个配置文件
        fs::write("log4r.toml", "[log4r]\nlevel = \"debug\"").expect("写入文件失败");
        fs::create_dir("config").expect("创建目录失败");
        fs::write("config/log4r.toml", "[log4r]\nlevel = \"info\"").expect("写入文件失败");

        let result = find_config();
        // 应该返回第一个找到的
        assert_eq!(result.unwrap(), PathBuf::from("log4r.toml"));

        // 恢复原目录
        env::set_current_dir(original_dir).expect("恢复目录失败");
    }

    // AC-3.3.6: 返回类型为 Option<PathBuf>
    #[test]
    fn test_find_config_return_type() {
        let result: Option<PathBuf> = find_config();
        // 编译通过即验证返回类型正确
        let _ = result;
    }

    // AC-3.3.2, AC-3.3.3: 用户配置目录路径构建
    #[test]
    fn test_user_config_dir_path() {
        // 验证 dirs::config_dir() 返回值
        if let Some(config_dir) = dirs::config_dir() {
            let expected_path = config_dir.join("log4r").join("log4r.toml");
            // 验证路径构建正确
            assert!(expected_path.to_string_lossy().contains("log4r"));
        }
    }

    // load_config 测试
    #[test]
    fn test_load_config_success() {
        let temp = tempdir().expect("创建临时目录失败");
        let config_path = temp.path().join("test.toml");
        fs::write(&config_path, "[log4r]\nlevel = \"warn\"").expect("写入文件失败");

        let config = load_config(&config_path).expect("加载配置应成功");
        assert_eq!(config.level, crate::Level::Warn);
    }

    #[test]
    fn test_load_config_file_not_found() {
        let result = load_config("nonexistent.toml");
        assert!(result.is_err(), "不存在的文件应返回错误");
        assert!(matches!(result.unwrap_err(), Log4rError::IoError(_)));
    }

    #[test]
    fn test_load_config_invalid_toml() {
        let temp = tempdir().expect("创建临时目录失败");
        let config_path = temp.path().join("invalid.toml");
        fs::write(&config_path, "[log4r\nlevel = ").expect("写入文件失败");

        let result = load_config(&config_path);
        assert!(result.is_err(), "无效 TOML 应返回错误");
        assert!(matches!(result.unwrap_err(), Log4rError::ConfigError(_)));
    }

    // load_config_from_default 测试
    #[test]
    #[serial]
    fn test_load_config_from_default_no_file() {
        let temp = tempdir().expect("创建临时目录失败");
        let original_dir = env::current_dir().expect("获取当前目录失败");
        env::set_current_dir(&temp).expect("切换目录失败");

        let config = load_config_from_default().expect("应返回默认配置");
        assert_eq!(config.level, crate::Level::Info);

        // 恢复原目录
        env::set_current_dir(original_dir).expect("恢复目录失败");
    }

    #[test]
    #[serial]
    fn test_load_config_from_default_with_file() {
        let temp = tempdir().expect("创建临时目录失败");
        let original_dir = env::current_dir().expect("获取当前目录失败");
        env::set_current_dir(&temp).expect("切换目录失败");

        fs::write("log4r.toml", "[log4r]\nlevel = \"error\"").expect("写入文件失败");

        let config = load_config_from_default().expect("应加载配置文件");
        assert_eq!(config.level, crate::Level::Error);

        // 恢复原目录
        env::set_current_dir(original_dir).expect("恢复目录失败");
    }
}
